#pragma once
#include"Socket.hpp"
#include <iostream>
#include <fstream>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
#include <sstream>
#include <unordered_map>
using std::cout;
using std::cin;
using std::endl;

const std::string wwwroot = "./wwwroot";          //web根目录
const std::string sep = "\r\n";
const std::string homepage = "index.html";
const std::string Page_404 = "./wwwroot/404.html";


class HttpRequest
{
public:
    std::vector<std::string> req_headers;
    std::string req_content;
    
    std::string method;
    std::string url;
    std::string http_version;
    std::string source_path;

    std::string suffix;

public:
    void Parse()
    {
        std::stringstream ss(req_headers[0]);
        ss >> method >> url >> http_version;
        source_path = wwwroot;

        // ./wwwroot/index.html
        if(url == "/" || url == "/index.html"){
            source_path += "/";
            source_path += homepage;
        }
        else source_path += url; 

        auto pos = source_path.rfind(".");
        if(pos == std::string :: npos) suffix = ".html";
        else suffix = source_path.substr(pos);
    }

    void Deserialize(std::string in)
    {
        while(1)
        {
            ssize_t pos = in.find(sep);
            if(pos == std::string::npos)break;

            std::string tmp = in.substr(0,pos);
            if(tmp.empty())break; //读到空行结束

            req_headers.push_back(tmp);
            in.erase(0,pos + sep.size());
        }

        req_content = in;
    }

    void Print()
    {
        for(auto& line : req_headers)
            cout << line << endl << endl;

        cout << "method: " << method << endl;
        cout << "url: " << url << endl;
        cout << "http_version: " << http_version << endl;
        cout << "source_path: " << source_path << endl;

    }

};
class HttpServer;
struct ThreadData
{
    int sockfd;
    HttpServer* svr;

    ThreadData(int _sockfd, HttpServer* _svr)
        :sockfd(_sockfd)
        ,svr(_svr)
    {}
};

class HttpServer
{
private:
    Socket _listensock;
    uint16_t _port;
    std::unordered_map<std::string, std::string> content_type;

public:
    HttpServer(uint16_t port = 8080)
        :_port(port)
    {
        content_type.insert({".html", "text/html"});
        content_type.insert({".png", "image/png"});
        content_type.insert({".jpg", "image/jpeg"});
    }

    ~HttpServer(){}

public:
    bool Start();                                                       //1.等待客户端到来
    static void* ThreadRun(void* arg);                                  //线程执行函数--支持多个连接
    void HandlerHttp(int sockfd);                                       //2.处理Http请求

    static std::string ReadHtmlContent(const std::string& path);        //返回一个文件的内容
    std::string SuffixToDesc(const std::string &suffix);                //根据文件后缀--获取返回给浏览器的响应

};

//////////////////////////////////////////////////HttpServer//////////////////////////////////////////////////////////
bool HttpServer::Start()
{
    _listensock.Create();
    _listensock.Bind(_port);
    _listensock.Listen();
    while(1)
    {  
        std::string client_ip;
        uint16_t client_port;
        int newsocket = _listensock.Accept(&client_ip, &client_port);
        if(newsocket < 0)continue;
        cout << "get a new link" << endl;

        //多线程处理数据
        pthread_t tid;
        ThreadData* td = new ThreadData(newsocket, this);
        pthread_create(&tid, nullptr, ThreadRun, td);
    }
}

void HttpServer::HandlerHttp(int sockfd)
{   
    char buffer[10240];
    ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
    if(n > 0)
    {
        //1.拿到请求--假设读到的是一个完整的报文
        buffer[n] = 0;
        cout << buffer << endl;

        //2.解析请求-->拆分
        HttpRequest req;
        req.Deserialize(buffer);
        req.Parse();
        //req.Print();

        //3.构建响应
        std::string text = ReadHtmlContent(req.source_path);
        //请求行
        std::string response_line = "HTTP/1.0 200 OK\r\n";  

        //请求头
        std::string response_header;
        cout << response_header << endl;
        response_header += "Content-Length: ";              
        response_header += std::to_string(text.size());     
        response_header += "\r\n";                          //要补\r\n
        response_header += "Content-Type: ";
        response_header += SuffixToDesc(req.suffix);
        response_header += "\r\n";                          //要补\r\n
        response_header += "Set-Cookie: name=Barry";
        response_header += "\r\n";                          //要补\r\n
        cout << response_header << endl;

        //正文                      
        std::string response;
        response += response_line;
        response += response_header;
        response += "\r\n";
        response += text;

        //4.返回响应
        send(sockfd, response.c_str(), response.size(), 0);
    }
    close(sockfd);
}

void* HttpServer::ThreadRun(void* arg)
{
    pthread_detach(pthread_self());
    ThreadData* td = static_cast<ThreadData*>(arg);
    HttpServer* svr = td->svr;
    svr->HandlerHttp(td->sockfd);

    delete td;
    return nullptr;
}


std::string HttpServer::ReadHtmlContent(const std::string& path)
{
    std::ifstream in(path, std::ios::binary);
    if(!in.is_open())return ReadHtmlContent(Page_404);

    in.seekg(0, std::ios_base::end);
    auto len = in.tellg();
    in.seekg(0, std::ios_base::beg);
    
    std::string content;
    content.resize(len);
    in.read((char*)content.c_str(), content.size());

    // std::string content;
    // std::string line;
    // while(std::getline(in,line))
    // {
    //     content += line;
    // }

    in.close();
    return content;
}


std::string HttpServer::SuffixToDesc(const std::string &suffix)
{
    auto iter = content_type.find(suffix);
    if(iter == content_type.end())return content_type[".html"];
    else return content_type[suffix];
}               

